package com.lagou.filter;

import com.lagou.service.remote.UserService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Optional;

@Component
public class TokenFilter implements GlobalFilter, Ordered {

    private static final Log logger = LogFactory.getLog(TokenFilter.class);

    /**
     * ⽤用户微服务和验证码微服务的请求不过滤
     */
    private static final String[] EXCLUDE_PATH_PREFIX = { "/api/user", "/api/code" };

    @Autowired
    private UserService userService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getURI().getRawPath();

        if (StringUtils.startsWithAny(path, EXCLUDE_PATH_PREFIX)) {
            // 正常放行
            return chain.filter(exchange);
        }

        Optional<String> loginToken = getCookieValue(request, "login_token");
        Optional<String> loginEmail = getCookieValue(request, "login_email");
        logger.info("start check token, path=" + path
                + ", loginToken=" + loginToken.orElse("")
                + ", loginEmail=" + loginEmail.orElse(""));

        if (!loginToken.isPresent() || !loginEmail.isPresent()) {
            logger.info("unauthorized request, path=" + path);
            return denyResponse(response);
        }
        String email = userService.info(loginToken.get());
        if (StringUtils.isBlank(email) || !email.equals(loginEmail.get())) {
            // token非法或者邮箱不匹配，拒绝放行
            logger.info("unauthorized request, path=" + path);
            return denyResponse(response);
        }

        // 正常放行
        return chain.filter(exchange);
    }

    private Mono<Void> denyResponse(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        DataBuffer wrap = response.bufferFactory().wrap("unauthorized request!".getBytes());
        return response.writeWith(Mono.just(wrap));
    }

    private Optional<String> getCookieValue(ServerHttpRequest req, String name) {
        Optional<HttpCookie> opt = req.getCookies()
                .toSingleValueMap()
                .values()
                .stream()
                .filter(v -> v.getName().equals(name))
                .findAny();
        return opt.isPresent() ? Optional.of(opt.get().getValue()) : Optional.empty();
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
